#include "libPPD.h"
#include "N-Step-SCAN.h"

int32_t responderPedidos(t_NIPC* paqueteAenviar, t_NIPC *paqueteRecibido)
{
	extern t_config config;
	extern int32_t contadorEscriturasSectores;
	int32_t valorRetorno;
	uint32_t tiempoLectura = config.tiempoLectura * 1000;
	uint32_t tiempoEscritura = config.tiempoEscritura * 1000;
	char *contenidoSector=NULL;

	if (paqueteRecibido->PayloadDescriptor == ESCRIBIRSECTOR)
	{
		if (strcmp(config.algoritmo, "CLOOK") == 0 && config.logActivado == 1)
			informacionPlanificacion(paqueteRecibido->nroSector, NULL);
		else if (strcmp(config.algoritmo, "NSTEPSCAN") == 0 && config.logActivado == 1)
			informacionNStepSCAN (paqueteRecibido->nroSector, NULL);

		char *mensaje;
		mensaje = (char *) calloc (1, strlen("Se ha escrito satisfactoriamente el sector") + 1);
		sprintf (mensaje, "%s" , "Se ha escrito satisfactoriamente el sector");
		int32_t tamMensaje = strlen(mensaje);

		valorRetorno = escribirSector(paqueteRecibido->nroSector, paqueteRecibido->payload);
		contadorEscriturasSectores ++;
		if(contadorEscriturasSectores == config.cantMmap)
		{
			contadorEscriturasSectores = 0;
			cerrarArchivoMapeado();
			abrirMapearArchivoDisco();
		}
		 if (tiempoLectura > 0)
		   usleep(tiempoEscritura);
		NIPC_crearpaquete(paqueteRecibido->DescriptorID, ESCRIBIRSECTOR, tamMensaje, mensaje, paqueteRecibido->nroSector, paqueteAenviar);
		free(mensaje);

	}
	else if (paqueteRecibido->PayloadDescriptor == LEERSECTOR)
	{
		if (strcmp(config.algoritmo, "CLOOK") == 0 && config.logActivado == 1)
			informacionPlanificacion(paqueteRecibido->nroSector, NULL);
		else if (strcmp(config.algoritmo, "NSTEPSCAN") == 0  && config.logActivado == 1)
			informacionNStepSCAN (paqueteRecibido->nroSector, NULL);

		contenidoSector = (char *) calloc (TAMSECTOR, sizeof(char));
		contadorEscriturasSectores ++;
		if(contadorEscriturasSectores == config.cantMmap)
		{
			contadorEscriturasSectores = 0;
			cerrarArchivoMapeado();
			abrirMapearArchivoDisco();
		}
		valorRetorno = leerSector(paqueteRecibido->nroSector, contenidoSector);
		if (paqueteRecibido->nroSector > 2000)
		    if (tiempoLectura > 0)
			usleep(tiempoLectura);
		NIPC_crearpaquete(paqueteRecibido->DescriptorID, LEERSECTOR, TAMSECTOR, contenidoSector, paqueteRecibido->nroSector, paqueteAenviar);
		free(contenidoSector);
	}
	else if(paqueteRecibido->PayloadDescriptor == TRACE)
	{
		int32_t tamanioMemoria = (sizeof(uint32_t)*2) +2;
		char *trace;
		int32_t tamTrace = 6*sizeof(uint32_t)+7+25*tamanioMemoria+sizeof(float);
		trace = (char *) calloc (1, tamTrace);

		if (strcmp(config.algoritmo, "CLOOK") == 0)
			informacionPlanificacion(paqueteRecibido->nroSector, &trace);
        else if (strcmp(config.algoritmo, "NSTEPSCAN") == 0)
         {
                 free(trace);
                 int32_t tamTrace = 6*sizeof(uint32_t)+7+30*tamanioMemoria+sizeof(float);
                 trace = (char *) calloc (1, tamTrace);
                 informacionNStepSCAN (paqueteRecibido->nroSector, &trace);
         }
		NIPC_crearpaquete (paqueteRecibido->DescriptorID, TRACE, tamTrace, trace, paqueteRecibido->nroSector, paqueteAenviar);
		free(trace);
	}

	actualizarCabezal(paqueteRecibido->nroSector);

	return Retorno_OK;
}


void responderPedidosRAID ()
{
	extern sem_t semaforoLista;
	extern int32_t socketPRAID;
	extern int32_t sockConsola;
	t_NIPC paqueteAenviar;
	t_nodoPRAID *nodo;
	int32_t valorRetorno;

	while (1)
	{
		sem_wait(&semaforoLista);
		sacarDeLaListaPRAID(&nodo);

		valorRetorno = responderPedidos(&paqueteAenviar, &nodo->paquete);
		if(nodo->paquete.PayloadDescriptor == TRACE)
			valorRetorno = NIPC_enviar(sockConsola, paqueteAenviar);
		else
			valorRetorno = NIPC_enviar (socketPRAID, paqueteAenviar);

		NIPC_destruirpaquete(&paqueteAenviar);
		NIPC_destruirpaquete(&nodo->paquete);
		free(nodo);
	}
}


void responderPedidosPFS ()
{
	extern sem_t semaforoLista;
	extern int32_t sockConsola;
	t_NIPC paqueteAenviar;
	int32_t valorRetorno;
	t_nodoPFS *nodo;

	while (1)
	{
	    sem_wait(&semaforoLista);

		sacarDeLaListaPFS (&nodo);
		valorRetorno = responderPedidos(&paqueteAenviar, &nodo->paquete);
		if((nodo->paquete).PayloadDescriptor == TRACE)
			valorRetorno = NIPC_enviar(sockConsola, paqueteAenviar);
		else
			valorRetorno = NIPC_enviar (nodo->socket, paqueteAenviar);

		NIPC_destruirpaquete(&paqueteAenviar);
		NIPC_destruirpaquete(&nodo->paquete);
		free(nodo);
	}
}


/* Se loguea: Cola de pedidos, tamaño, posición actual, sector solicitado, sectores recorridos, tiempo consumido, próximo sector de la cola*/
void informacionPlanificacion(uint32_t nroSector, char ** trace)
{
	extern pthread_mutex_t bloqueaLista;
	extern t_config config;
	extern tCabezal cabezal;
	extern t_log *loguear;

	int32_t tamanioLista = 0; int32_t cantSectoresRecorridos = 0;
	int32_t bloquearLista = 0;
	int32_t cantSaltosEntrePistas = 0; int32_t hayProxSector = 1;
	int32_t hayMuchasPistas = 0;  int32_t hayMuchosSectores = 0;
	int32_t hayMuchosPedidos = 0;
	float tiempoSector, tiempoConsumido;
	int32_t tamanioMemoria;
	uint32_t posicionCabezal;
	char *sectoresCHS = NULL;
	char *sectoresRecorridos = NULL;
	char *pistaSector = NULL;
	char *ultimaPista = NULL;
	char *ultimoSector = NULL;
	t_CHS sectorCHS, sectorPedidoCHS, proxSectorCHS, posicionCabezalCHS;

	tamanioMemoria = (sizeof(uint32_t)*2) +2;            //dos uint uno para c otro para s + el espacio + los dos puntos.
	sectoresCHS = (char*) calloc (25, tamanioMemoria);
	pistaSector = (char *) calloc(1, tamanioMemoria);
	ultimoSector = (char *) calloc(1, tamanioMemoria + 4); //puntos suspensivos

	pasarACHS (nroSector, &sectorPedidoCHS);

	/*Armo cola de pedidos y guardo el tamaño y el próximo sector*/

	bloquearLista =  pthread_mutex_lock(&bloqueaLista);
	if (strcmp(config.modoInicio, "CONNECT") == 0)
	{
		extern t_listaPRAID *listaPedidosPRAID;
		t_nodoPRAID * nodo;
		nodo = listaPedidosPRAID->head;

		sprintf(pistaSector, "%d:%d ", sectorPedidoCHS.C, sectorPedidoCHS.S);
		strcat(sectoresCHS, pistaSector);

		while (nodo != NULL)
		{
			pasarACHS (nodo->paquete.nroSector, &sectorCHS);
			sprintf(pistaSector, "%d:%d ", sectorCHS.C, sectorCHS.S);
			if(tamanioLista == 0) //guardo el primer sector como próximo sector
			{
				proxSectorCHS.C = sectorCHS.C;
				proxSectorCHS.S = sectorCHS.S;
				hayProxSector = 0;
			}
			if (tamanioLista < 20)
			{
				strcat(sectoresCHS, pistaSector);
			}
			else
			{
				hayMuchosPedidos = 1;
				sprintf(ultimoSector, "... %d:%d", sectorCHS.C, sectorCHS.S);
			}
			tamanioLista++;
			nodo = nodo->next;
		}
		tamanioLista++;
		if (hayMuchosPedidos == 1)
			strcat(sectoresCHS, ultimoSector);
	}
	else if (strcmp(config.modoInicio, "LISTEN") == 0)
	{
		extern t_listaPFS *listaPedidosPFS;
		t_nodoPFS * nodo;
		nodo = listaPedidosPFS->head;

		sprintf(pistaSector, "%d:%d ", sectorPedidoCHS.C, sectorPedidoCHS.S);
		strcat(sectoresCHS, pistaSector);

		while (nodo != NULL)
		{
			pasarACHS (nodo->paquete.nroSector, &sectorCHS);
			sprintf(pistaSector, "%d:%d ", sectorCHS.C, sectorCHS.S);
			if(tamanioLista == 0) //guardo el primer sector como próximo sector
			{
				proxSectorCHS.C = sectorCHS.C;
				proxSectorCHS.S = sectorCHS.S;
				hayProxSector = 0;
			}
			if (tamanioLista < 20)
			{
				strcat(sectoresCHS, pistaSector);
			}
			else
			{
				hayMuchosPedidos = 1;
				sprintf(ultimoSector, "... %d:%d", sectorCHS.C, sectorCHS.S);
			}
			tamanioLista++;
			nodo = nodo->next;
		}
		tamanioLista++;
		if (hayMuchosPedidos == 1)
			strcat(sectoresCHS, ultimoSector);
	}

	bloquearLista =  pthread_mutex_unlock(&bloqueaLista);

	/* Armo los sectores recorridos desde la Posición Actual hasta el Sector Pedido*/

	sectoresRecorridos = (char*) calloc (25, tamanioMemoria);
	ultimaPista = (char *) calloc(1, tamanioMemoria + 4);

	pasarAuint(cabezal.posActual, &posicionCabezal);
	sprintf(pistaSector, "%d:%d ", cabezal.posActual.C, cabezal.posActual.S);
	strcat(sectoresRecorridos, pistaSector);

	while (posicionCabezal != nroSector)
	{
		pasarACHS (posicionCabezal, &posicionCabezalCHS);
		if ((posicionCabezalCHS.C < sectorPedidoCHS.C)) //salto de pista
		{
			posicionCabezalCHS.C++;
			sprintf(pistaSector, "%d:%d ", posicionCabezalCHS.C, posicionCabezalCHS.S);
			pasarAuint(posicionCabezalCHS, &posicionCabezal);

			if(cantSaltosEntrePistas < 10)
				strcat(sectoresRecorridos, pistaSector);
			else
			{
				hayMuchasPistas = 1;
				sprintf (ultimaPista, "... %d:%d ", posicionCabezalCHS.C, posicionCabezalCHS.S);
			}
			cantSaltosEntrePistas++;
		}
		else if (posicionCabezalCHS.C == sectorPedidoCHS.C) //recorre en la misma pista
		{
			if (cantSectoresRecorridos == 0)
				cantSectoresRecorridos ++;   //porque cuenta en donde estaba, en los otros casos no porque lo saltea.
			if(hayMuchasPistas == 1)
			{
				strcat(sectoresRecorridos, ultimaPista);
				hayMuchasPistas = 0;
			}
			if (posicionCabezalCHS.S == (config.s-1))
			{
				posicionCabezalCHS.S = 0;
				pasarAuint(posicionCabezalCHS, &posicionCabezal);
			}
			else
			{
				posicionCabezalCHS.S++;
				pasarAuint(posicionCabezalCHS, &posicionCabezal);
				cantSectoresRecorridos++;
			}
			if (cantSectoresRecorridos < 10)
			{
				sprintf(pistaSector, "%d:%d ", posicionCabezalCHS.C, posicionCabezalCHS.S);
				strcat(sectoresRecorridos, pistaSector);
			}
			else
			{
				hayMuchosSectores = 1;
				sprintf(ultimoSector, "... %d:%d", posicionCabezalCHS.C, posicionCabezalCHS.S);
			}
		}
		else if(posicionCabezalCHS.C > sectorPedidoCHS.C)  //deja caer el cabezal
		{
			posicionCabezalCHS.C = sectorPedidoCHS.C;
			sprintf(pistaSector, "%d:%d ", posicionCabezalCHS.C, posicionCabezalCHS.S);
			pasarAuint(posicionCabezalCHS, &posicionCabezal);
			strcat(sectoresRecorridos, pistaSector);
		}
	}
	if (hayMuchosSectores == 1)
		strcat(sectoresRecorridos, ultimoSector);
	if (hayMuchasPistas == 1)
		strcat(sectoresRecorridos, ultimaPista);

	tiempoSector = (float)(60000/config.rpm);         //en ms.
	tiempoSector = (float)(tiempoSector/config.s);
	tiempoConsumido = config.tiempoSaltoPistas *cantSaltosEntrePistas + tiempoSector * cantSectoresRecorridos;

	if(config.logActivado == 1)  //agregar  && trace == NULL
	{
		if (hayProxSector == 1)
			log_info (loguear, "PPD", "\nCola de Pedidos: %s\nTamaño: %d\nPosicion Actual: %d:%d\nSector Solicitado: %d:%d\n"
					"Sectores Recorridos: %s\nTiempo Consumido: %f ms\nProximo Sector: -\n\n", sectoresCHS, tamanioLista,
					cabezal.posActual.C, cabezal.posActual.S, sectorPedidoCHS.C, sectorPedidoCHS.S, sectoresRecorridos,
					tiempoConsumido);
		else
			log_info (loguear, "PPD", "\nCola de Pedidos: %s\nTamaño: %d\nPosicion Actual: %d:%d\nSector Solicitado: %d:%d\n"
					"Sectores Recorridos: %s\nTiempo Consumido: %f ms\nProximo Sector: %d:%d\n\n", sectoresCHS, tamanioLista,
					cabezal.posActual.C, cabezal.posActual.S, sectorPedidoCHS.C, sectorPedidoCHS.S, sectoresRecorridos,
					tiempoConsumido, proxSectorCHS.C, proxSectorCHS.S);
	}
	if(trace != NULL)
	{
		if (hayProxSector == 1)
			sprintf(*trace, "%d:%d\n%d:%d\n%s\n%f\n-:-\n", cabezal.posActual.C, cabezal.posActual.S, sectorPedidoCHS.C,
					sectorPedidoCHS.S, sectoresRecorridos,tiempoConsumido);
		else
			sprintf(*trace, "%d:%d\n%d:%d\n%s\n%f\n%d:%d\n", cabezal.posActual.C, cabezal.posActual.S, sectorPedidoCHS.C,
					sectorPedidoCHS.S, sectoresRecorridos,tiempoConsumido, proxSectorCHS.C, proxSectorCHS.S);
	}

	free(sectoresCHS);
	free(sectoresRecorridos);
	free(pistaSector);
	free(ultimaPista);
	free(ultimoSector);

}
